package io.seata.account.service.impl;

import io.seata.account.entity.Account;
import io.seata.account.entity.AccountFreeze;
import io.seata.account.mapper.AccountFreezeMapper;
import io.seata.account.mapper.AccountMapper;
import io.seata.account.service.AccountTCCService;
import io.seata.common.dto.AccountDTO;
import io.seata.common.enums.RspStatusEnum;
import io.seata.common.exception.DefaultException;
import io.seata.common.response.ObjectResponse;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {

    @Resource
    private AccountMapper accountMapper;
    @Resource
    private AccountFreezeMapper freezeMapper;

    @Override
    @Transactional
    public ObjectResponse deduct(AccountDTO accountDTO) {
        ObjectResponse objectResponse = new ObjectResponse();
        // 0.获取事务id
        String xid = RootContext.getXID();
        //判断是否业务悬挂
        if(freezeMapper.selectById(xid) != null) {
            log.error("业务悬挂");
            throw new DefaultException(RspStatusEnum.EXCEPTION);
        }

        // 1.扣减可用余额
        Account account = new Account();
        account.setUserId(accountDTO.getUserId());
        account.setMoney(accountDTO.getMoney());
        accountMapper.deduct(account);
        // 2.记录冻结金额，事务状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(accountDTO.getUserId());
        freeze.setFreezeMoney(accountDTO.getMoney());
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        freezeMapper.insert(freeze);

        objectResponse.setStatus(RspStatusEnum.SUCCESS.getCode());
        objectResponse.setMessage(RspStatusEnum.SUCCESS.getMessage());
        return objectResponse;
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        // 1.获取事务id
        String xid = ctx.getXid();
        // 2.根据id删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        // 0.查询冻结记录
        String xid = ctx.getXid();
        AccountFreeze freeze = freezeMapper.selectById(xid);
        //判断是否为空回滚，空回滚不执行业务
        if (freeze != null && freeze.getState().equals(AccountFreeze.State.TRY)) {
            // 1.恢复可用余额
            Account account = new Account();
            account.setUserId(freeze.getUserId());
            account.setMoney(freeze.getFreezeMoney());
            accountMapper.refund(account);
            // 2.将冻结金额清零，状态改为CANCEL
            freeze.setFreezeMoney(BigDecimal.ZERO);
            freeze.setState(AccountFreeze.State.CANCEL);
            int count = freezeMapper.updateById(freeze);
            return count == 1;
        }
        log.error("空回滚");
        return true;
    }
}
